﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.MountAndBlade.View.Screens.VisualTestsScreen
// Assembly: TaleWorlds.MountAndBlade.View, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 61152EB8-513B-4D4A-8AC0-0D1465C6CF6C
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\Modules\Native\bin\Win64_Shipping_Client\TaleWorlds.MountAndBlade.View.dll

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using TaleWorlds.Engine;
using TaleWorlds.Engine.Options;
using TaleWorlds.Engine.Screens;
using TaleWorlds.Library;
using TaleWorlds.ScreenSystem;

#nullable disable
namespace TaleWorlds.MountAndBlade.View.Screens
{
  public class VisualTestsScreen : ScreenBase
  {
    private Scene _scene;
    private MBAgentRendererSceneController _agentRendererSceneController;
    private Camera _camera;
    private SceneLayer _sceneLayer;
    private List<VisualTestsScreen.CameraPoint> CamPoints;
    private DateTime testTime;
    private string _validWriteDirectory = Utilities.GetVisualTestsValidatePath();
    private string _validReadDirectory = Utilities.GetBasePath() + "ValidVisuals/";
    private string _pathDirectory = Utilities.GetVisualTestsTestFilesPath();
    private string _failDirectory = TestCommonBase.GetAttachmentsFolderPath();
    private string _reportFile = "report.txt";
    private int CurCameraIndex;
    private int TestSubIndex;
    private bool isValidTest_ = true;
    private NativeOptions.ConfigQuality preset_;
    public static bool isSceneSuccess = true;
    private string date;
    private string scene_name;
    private int frameCounter = -200;
    private List<string> testTypesToCheck_ = new List<string>();

    private int CamPointCount => this.CamPoints.Count;

    public bool StartedRendering() => this._sceneLayer.SceneView.ReadyToRender();

    public string GetSubTestName(VisualTestsScreen.CameraPointTestType type)
    {
      switch (type)
      {
        case VisualTestsScreen.CameraPointTestType.Final:
          return "_final";
        case VisualTestsScreen.CameraPointTestType.Albedo:
          return "_albedo";
        case VisualTestsScreen.CameraPointTestType.Normal:
          return "_normal";
        case VisualTestsScreen.CameraPointTestType.Specular:
          return "_specular";
        case VisualTestsScreen.CameraPointTestType.AO:
          return "_ao";
        case VisualTestsScreen.CameraPointTestType.OnlyAmbient:
          return "_onlyambient";
        case VisualTestsScreen.CameraPointTestType.OnlyDirect:
          return "_onlydirect";
        default:
          return "";
      }
    }

    public Utilities.EngineRenderDisplayMode GetRenderMode(
      VisualTestsScreen.CameraPointTestType type)
    {
      switch (type)
      {
        case VisualTestsScreen.CameraPointTestType.Albedo:
          return Utilities.EngineRenderDisplayMode.ShowAlbedo;
        case VisualTestsScreen.CameraPointTestType.Normal:
          return Utilities.EngineRenderDisplayMode.ShowNormals;
        case VisualTestsScreen.CameraPointTestType.Specular:
          return Utilities.EngineRenderDisplayMode.ShowSpecular;
        case VisualTestsScreen.CameraPointTestType.AO:
          return Utilities.EngineRenderDisplayMode.ShowOcclusion;
        case VisualTestsScreen.CameraPointTestType.OnlyAmbient:
          return Utilities.EngineRenderDisplayMode.ShowDisableSunLighting;
        case VisualTestsScreen.CameraPointTestType.OnlyDirect:
          return Utilities.EngineRenderDisplayMode.ShowDisableAmbientLighting;
        default:
          return Utilities.EngineRenderDisplayMode.ShowNone;
      }
    }

    public VisualTestsScreen(
      bool isValidTest,
      NativeOptions.ConfigQuality preset,
      string sceneName,
      DateTime testTime,
      List<string> testTypesToCheck)
    {
      this.isValidTest_ = isValidTest;
      this.preset_ = preset;
      this.scene_name = sceneName;
      this.testTime = testTime;
      VisualTestsScreen.isSceneSuccess = true;
      this._failDirectory = this._failDirectory + "/" + sceneName + "_" + (object) preset;
      this.testTypesToCheck_ = testTypesToCheck;
    }

    protected override void OnInitialize()
    {
      base.OnInitialize();
      this._sceneLayer = new SceneLayer();
      this.AddLayer((ScreenLayer) this._sceneLayer);
    }

    protected override void OnActivate()
    {
      base.OnActivate();
      if (!this.isValidTest_)
      {
        this.date = this.testTime.ToString("dd-MM-yyyy hh-mmtt");
        this._pathDirectory = this._pathDirectory + this.date + "/";
        Directory.CreateDirectory(this._pathDirectory);
        this._reportFile = this._pathDirectory + "report.txt";
      }
      this.CreateScene();
      this._scene.Tick(0.0f);
    }

    protected override void OnDeactivate() => base.OnDeactivate();

    protected override void OnFrameTick(float dt)
    {
      base.OnFrameTick(dt);
      LoadingWindow.DisableGlobalLoadingWindow();
      MessageManager.EraseMessageLines();
      if (!this._sceneLayer.ReadyToRender())
        return;
      this.SetTestCamera();
      if (Utilities.GetNumberOfShaderCompilationsInProgress() > 0)
        return;
      this._scene.Tick(this._scene.GetName() == "visualtestmorph" ? 0.01f : 0.0f);
      int num = 5;
      ++this.frameCounter;
      if (this.frameCounter < num)
        return;
      this.TakeScreenshotAndAnalyze();
      if (this.CurCameraIndex >= this.CamPointCount)
        ScreenManager.PopScreen();
      else
        this.frameCounter = 0;
    }

    private void CreateScene()
    {
      this._scene = Scene.CreateNewScene();
      this._scene.SetName("VisualTestScreen");
      this._agentRendererSceneController = MBAgentRendererSceneController.CreateNewAgentRendererSceneController(this._scene, 32);
      this._scene.Read(this.scene_name);
      this._scene.SetUseConstantTime(true);
      this._scene.SetOcclusionMode(true);
      this._scene.OptimizeScene(optimizeOro: true);
      this._sceneLayer.SetScene(this._scene);
      this._sceneLayer.SceneView.SetSceneUsesShadows(true);
      this._sceneLayer.SceneView.SetForceShaderCompilation(true);
      this._sceneLayer.SceneView.SetClearGbuffer(true);
      this._camera = Camera.CreateCamera();
      this.GetCameraPoints();
      MessageManager.EraseMessageLines();
    }

    private bool ShouldCheckTestModeWithTag(string mode, GameEntity entity)
    {
      return (this.testTypesToCheck_.Count <= 0 || this.testTypesToCheck_.Contains(mode)) && entity.HasTag(mode);
    }

    private bool ShouldCheckTestMode(string mode) => this.testTypesToCheck_.Contains(mode);

    private void GetCameraPoints()
    {
      this.CamPoints = new List<VisualTestsScreen.CameraPoint>();
      foreach (GameEntity entity in this._scene.FindEntitiesWithTag("test_camera").OrderBy<GameEntity, string>((Func<GameEntity, string>) (o => o.Name)).ToList<GameEntity>())
      {
        if (!entity.HasTag("exclude_" + (object) (int) this.preset_))
        {
          VisualTestsScreen.CameraPoint cameraPoint = new VisualTestsScreen.CameraPoint();
          cameraPoint.CamFrame = entity.GetFrame();
          cameraPoint.CameraName = entity.Name;
          HashSet<VisualTestsScreen.CameraPointTestType> cameraPointTestTypeSet = new HashSet<VisualTestsScreen.CameraPointTestType>();
          if (this.ShouldCheckTestModeWithTag("gbuffer", entity))
          {
            cameraPointTestTypeSet.Add(VisualTestsScreen.CameraPointTestType.Albedo);
            cameraPointTestTypeSet.Add(VisualTestsScreen.CameraPointTestType.Normal);
            cameraPointTestTypeSet.Add(VisualTestsScreen.CameraPointTestType.Specular);
            cameraPointTestTypeSet.Add(VisualTestsScreen.CameraPointTestType.AO);
          }
          if (this.ShouldCheckTestMode("albedo"))
            cameraPointTestTypeSet.Add(VisualTestsScreen.CameraPointTestType.Albedo);
          if (this.ShouldCheckTestMode("normal"))
            cameraPointTestTypeSet.Add(VisualTestsScreen.CameraPointTestType.Normal);
          if (this.ShouldCheckTestMode("specular"))
            cameraPointTestTypeSet.Add(VisualTestsScreen.CameraPointTestType.Specular);
          if (this.ShouldCheckTestMode("ao"))
            cameraPointTestTypeSet.Add(VisualTestsScreen.CameraPointTestType.AO);
          if (this.ShouldCheckTestModeWithTag("only_ambient", entity))
            cameraPointTestTypeSet.Add(VisualTestsScreen.CameraPointTestType.OnlyAmbient);
          foreach (VisualTestsScreen.CameraPointTestType cameraPointTestType in cameraPointTestTypeSet)
            cameraPoint.TestTypes.Add(cameraPointTestType);
          cameraPoint.TestTypes.Add(VisualTestsScreen.CameraPointTestType.Final);
          this.CamPoints.Add(cameraPoint);
        }
      }
    }

    private void SetTestCamera()
    {
      VisualTestsScreen.CameraPoint camPoint = this.CamPoints[this.CurCameraIndex];
      this._camera.Frame = camPoint.CamFrame;
      this._camera.SetFovVertical(1.04719758f, Screen.AspectRatio, 0.1f, 500f);
      this._sceneLayer.SetCamera(this._camera);
      Utilities.SetRenderMode(this.GetRenderMode(camPoint.TestTypes[this.TestSubIndex]));
    }

    protected override void OnFinalize()
    {
      MBDebug.Print("On finalized called for scene: " + this.scene_name);
      base.OnFinalize();
      this._sceneLayer.ClearAll();
      MBAgentRendererSceneController.DestructAgentRendererSceneController(this._scene, this._agentRendererSceneController, false);
      this._agentRendererSceneController = (MBAgentRendererSceneController) null;
      this._scene = (Scene) null;
    }

    public void Reset()
    {
    }

    private void TakeScreenshotAndAnalyze()
    {
      VisualTestsScreen.CameraPoint camPoint = this.CamPoints[this.CurCameraIndex];
      VisualTestsScreen.CameraPointTestType testType = camPoint.TestTypes[this.TestSubIndex];
      int renderMode = (int) this.GetRenderMode(testType);
      bool flag = true;
      string str1;
      if (this.isValidTest_)
        str1 = this._validReadDirectory + this.scene_name + "_" + camPoint.CameraName + "_" + this.GetSubTestName(testType) + "_preset_" + NativeOptions.GetGFXPresetName(this.preset_) + ".bmp";
      else
        str1 = this._validReadDirectory + this.scene_name + "_" + camPoint.CameraName + "_" + this.GetSubTestName(testType) + "_preset_" + NativeOptions.GetGFXPresetName(this.preset_) + ".bmp";
      string str2 = this._pathDirectory + (this.scene_name + "_" + camPoint.CameraName + "_" + this.GetSubTestName(testType) + "_preset_" + NativeOptions.GetGFXPresetName(this.preset_) + ".bmp");
      MBDebug.Print(str1);
      MBDebug.Print(str2);
      if (this.isValidTest_)
        Utilities.TakeScreenshot(str1);
      else
        Utilities.TakeScreenshot(str2);
      NativeOptions.GetGFXPresetName(this.preset_);
      if (!this.isValidTest_)
      {
        if (File.Exists(str1))
        {
          if (!this.AnalyzeImageDifferences(str1, str2))
            flag = false;
        }
        else
          flag = false;
      }
      if (!flag)
      {
        if (!Directory.Exists(this._failDirectory))
          Directory.CreateDirectory(TestCommonBase.GetAttachmentsFolderPath());
        if (!Directory.Exists(this._failDirectory))
          Directory.CreateDirectory(this._failDirectory);
        string path = this._failDirectory + "/" + camPoint.CameraName + this.GetSubTestName(testType);
        if (!Directory.Exists(path))
          Directory.CreateDirectory(path);
        string str3 = path + "/branch_result.bmp";
        string str4 = path + "/valid.bmp";
        if (File.Exists(str3))
          File.Delete(str3);
        if (File.Exists(str4))
          File.Delete(str4);
        File.Copy(str2, str3);
        if (File.Exists(str1))
        {
          if (File.Exists(str4))
            File.Delete(str4);
          File.Copy(str1, str4);
        }
        VisualTestsScreen.isSceneSuccess = false;
      }
      ++this.TestSubIndex;
      if (camPoint.TestTypes.Count != this.TestSubIndex)
        return;
      ++this.CurCameraIndex;
      this.TestSubIndex = 0;
    }

    private bool AnalyzeImageDifferences(string path1, string path2)
    {
      byte[] numArray1 = File.ReadAllBytes(path1);
      byte[] numArray2 = File.ReadAllBytes(path2);
      if (numArray1.Length != numArray2.Length)
        return false;
      float num1 = 0.0f;
      for (int index = 0; index < numArray1.Length; ++index)
      {
        float num2 = MathF.Max(MathF.Abs((float) numArray1[index] - (float) numArray2[index]), 0.0f);
        num1 += num2;
      }
      return (double) (num1 / (float) numArray1.Length) < 0.5;
    }

    public enum CameraPointTestType
    {
      Final,
      Albedo,
      Normal,
      Specular,
      AO,
      OnlyAmbient,
      OnlyDirect,
    }

    public class CameraPoint
    {
      public MatrixFrame CamFrame;
      public string CameraName;
      public List<VisualTestsScreen.CameraPointTestType> TestTypes;

      public CameraPoint()
      {
        this.TestTypes = new List<VisualTestsScreen.CameraPointTestType>();
        this.CamFrame = MatrixFrame.Identity;
        this.CameraName = "";
      }
    }
  }
}
